package com.ftaillefer.rss.parsers;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

import com.ftaillefer.rss.enums.FeedParentElement;
import com.ftaillefer.rss.model.Category;
import com.ftaillefer.rss.model.Channel;
import com.ftaillefer.rss.model.Image;
import com.ftaillefer.rss.model.Item;

public class RssParser extends DefaultHandler {
	private Channel channel;
	private StringBuilder text;
	private Item item;
	private FeedParentElement parentElement;

	public RssParser() {
		this.text = new StringBuilder();
	}

	public void parse(String url) throws MalformedURLException {
		InputStream urlInputStream = null;
		SAXParserFactory spf = null;
		SAXParser sp = null;
		URL targetUrl;

		targetUrl = new URL(url);

		try {
			urlInputStream = targetUrl.openConnection().getInputStream();
			spf = SAXParserFactory.newInstance();
			if (spf != null) {
				sp = spf.newSAXParser();
				sp.parse(urlInputStream, this);
			}
		}
		/*
		 * Exceptions need to be handled MalformedURLException
		 * ParserConfigurationException IOException SAXException
		 */

		catch (Exception e) {
			System.out.println("Exception: " + e);
			e.printStackTrace();
		} finally {
			try {
				if (urlInputStream != null)
					urlInputStream.close();
			} catch (Exception e) {
			}
		}
	}

	public Channel getChannel() {
		return (this.channel);
	}

	public void startElement(String uri, String localName, String qName,
			Attributes attributes) {

		final String elementName = qName.toLowerCase();

		if (elementName == "channel") {
			this.parentElement = FeedParentElement.CHANNEL;
			channel = new Channel();
			return;
		} else if (elementName == "image") {
			Image image = new Image();
			channel.setImage(image);
			this.parentElement = FeedParentElement.IMAGE;
			return;
		} else if (elementName == "item") {
			item = new Item();
			this.parentElement = FeedParentElement.ITEM;
			return;
		}

		if (elementName == "category") {
			Category category = new Category();
			category.setDomain(attributes.getValue("domain"));

			if (this.parentElement == FeedParentElement.CHANNEL) {
				channel.setCategory(category);
				this.channel.setCategory(category);
			} else if (this.parentElement == FeedParentElement.ITEM) {
				item.setCategory(category);
				this.channel.setCategory(category);
			}

		}

	}

	public void endElement(String uri, String localName, String qName) {

		final String elementName = qName.toLowerCase();
		final String elementText = text.toString().trim();

		switch (this.parentElement) {

		case CHANNEL:
			switch (elementName) {
			case "category":
				channel.getCategory().setValue(elementText);
				break;
			case "cloud":
				this.channel.setCloud(elementText);
				break;
			case "description":
				this.channel.setDescription(elementText);
				break;
			case "link":
				this.channel.setLink(elementText);
			case "title":
				this.channel.setTitle(elementText);
				break;
			}
			break;

		case IMAGE:
			switch (elementName) {
			case "description":
				channel.getImage().setDescription(elementText);
				break;
			case "height":
				this.channel.getImage().setHeight(Integer.parseInt(elementText));
				break;
			case "link":
				this.channel.getImage().setLink(elementText);
				break;
			case "title":
				this.channel.getImage().setTitle(elementText);
				break;
			case "url":
				this.channel.getImage().setUrl(elementText);
				break;
			case "width":
				this.channel.getImage().setWidth(Integer.parseInt(elementText));
				break;
			}
			break;

		case ITEM:
			switch (elementName) {
			case "category":
				this.item.getCategory().setValue(elementText);
				break;
			case "description":
				this.item.setDescription(elementText);
				break;
			case "item":
				this.channel.getItems().add(this.item);
				break;
			case "link":
				this.item.setLink(elementText);
				break;
			case "title":
				this.item.setTitle(elementText);
				break;
			}
			break;
		default:
			break;

		}

		this.text.setLength(0);
	}

	public void characters(char[] ch, int start, int length) {
		this.text.append(ch, start, length);
	}

}
